package com.mars.sso.client.filter;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.mars.base.common.utils.CookieUtils;
import com.mars.base.common.utils.http.HttpHelper;
import com.mars.base.common.utils.http.HttpResult;

/**
 * 令牌管理工具类
 * 
 * @author yhaoquan
 * 
 */
public class TokenManager {
	
	static Logger logger = LoggerFactory.getLogger(TokenManager.class);

	// 复合体结构，含SSOUser与最后访问时间lassAccessTime两个成员
	private static class Token {
		private SSOUser user;
		private Date lastAccessTime;
	}

	// 缓存Map
	private final static Map<String, Token> LOCAL_CACHE = new HashMap<String, TokenManager.Token>();

	// 业务系统与SSO系统间通信的内网地址
	static String serverInnerAddress;

	private TokenManager() {
	}

	/**
	 * 验证vt的有效性
	 * 
	 * @param vt
	 * @return
	 * @throws IOException
	 */
	public static SSOUser validate(String vt) throws Exception {
		SSOUser user = localValidate(vt);

		if (user == null) {
			user = remoteValidate(vt);
		}
		
		return user;
	}

	/**
	 * 本地缓存验证vt有效性
	 * 
	 * @param vt
	 * @return
	 */
	private static SSOUser localValidate(String vt) {
		// 从缓存中查找数据
		Token token = LOCAL_CACHE.get(vt);

		if (token != null) { // 用户数据存在
			logger.debug("本地缓存验证vt有效性");
			// 更新最后返回时间
			token.lastAccessTime = new Date();
			// 返回结果
			return token.user;
		}

		return null;
	}

	/**
	 * 远程验证vt有效性
	 * 
	 * @param vt
	 * @return
	 * @throws IOException
	 */
	private static SSOUser remoteValidate(String vt) throws Exception {
		String validateUrl = serverInnerAddress + "/validate_service?vt=" + vt;
		HttpResult result = HttpHelper.executeGet(validateUrl);
		
		SSOUser user= null ;
		
		if (result.getStatusCode() == 404) {
			throw new Exception("远程验证vt失败，请检查URL是否正确：" + validateUrl);
		}

		if (result.getStatusCode() == 200) {
			logger.debug("远程验证vt有效性");
			String content = result.getContent() ;
			Map<String, Object> map = (Map<String, Object>) JSON.parseObject(content) ;
			SSOUserImpl ssoUserImpl = new SSOUserImpl(map.get("id")) ;
			ssoUserImpl.setProperties(map);
			user = ssoUserImpl;

			// 处理本地缓存
			cacheUser(vt, user);
		}
		return user;
	}

	/**
	 * 验证成功后将信息写入本地缓存
	 * 
	 * @param vt
	 * @param user
	 */
	private static void cacheUser(String vt, SSOUser user) {
		Token token = new Token();
		token.user = user;
		token.lastAccessTime = new Date();
		LOCAL_CACHE.put(vt, token);
	}
	
	/**
	 * 重置Cookie过期时间
	 * @param vt
	 */
	public static void resetCookieTime(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookieValue, int cookieMaxage) {
		CookieUtils.setCookie(request, response, cookieName, cookieValue, cookieMaxage);
	}
	
	
	/**
	 * 处理服务器端发出的timeout通知
	 * @param vt
	 * @param cookieExpires
	 * @return
	 */
	public static Date timeout(String vt, long cookieExpires) {
		Token token = LOCAL_CACHE.get(vt) ;
		
		if(null != token) {
			Date lastAccessTime = token.lastAccessTime ;
			// 最终过期日期(最后访问时间+过期时间)
			Date expires = new Date(lastAccessTime.getTime() + cookieExpires) ;
			Date now = new Date() ;
			
			if(expires.compareTo(now) < 0) { //已过期
				//从本地缓存移除
				LOCAL_CACHE.remove(vt) ;
				//返回null表示此客户端缓存已过期
				return null ;
			} else {
				//重新设置缓存的过期时间
				token.lastAccessTime = expires ;
				//返回延期时间
				return expires ;
			}
		} else {
			return null ;
		}
	}
	
	/**
	 * 用户退出时失效对应缓存
	 * @param vt
	 */
	public static void invalidate(String vt) {
		//从本地缓存移除
		LOCAL_CACHE.remove(vt) ;
	}
	
	/**
	 * 服务器端应用关闭时情况本地缓存，失效所有信息
	 */
	public static void destory() {
		LOCAL_CACHE.clear();
	}
	
}
